﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Spring.Context;
using Spring.Context.Support;

namespace MediaScraper.Common
{
    public static class ObjectBroker
    {
        /// <summary>
        /// Gets this instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T Get<T>()
        {
            return (T)Context.GetObject(typeof(T).Name);
        }

        public static T Get<T>(Type serviceType)
        {
            return (T)Context.GetObject(serviceType.Name);
        }

        public static object Get(Type serviceType)
        {
            return Context.GetObject(serviceType.Name);
        }

        public static object TryGet(Type serviceType)
        {
            if (Context.ContainsObject(serviceType.Name))
            {
                try
                {
                    return Context.GetObject(serviceType.Name);
                }
                catch (Exception ex)
                {
                    return null;
                }
            }
            return null;
        }

        public static IEnumerable<object> GetAll(Type serviceType)
        {
            try
            {
                var services = Context.GetObjectsOfType(serviceType);
                return services.Values as IEnumerable<object>;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public static IEnumerable<T> GetAllOfType<T>()
        {
            var services = Context.GetObjectsOfType(typeof (T));
            return services.Values.Cast<T>();
        }

        /// <summary>
        /// Gets the specified object name.
        /// </summary>
        /// <param name="objectName">Name of the object.</param>
        /// <returns></returns>
        public static T Get<T>(string objectName)
        {
            if (Context.ContainsObject(objectName))
            {
                return (T)Context.GetObject(objectName);
            }
            return default(T);

        }

        public static IEnumerable<T> GetObjectsByType<T>() where T : class
        {

            var objects = Context.GetObjectsOfType(typeof(T), true, false);

            foreach (var item in objects.Values)
            {
                yield return (T)item;
            }
        }

        /// <summary>
        /// Gets the specified object name.
        /// </summary>
        /// <param name="objectName">Name of the object.</param>
        /// <returns></returns>
        public static T Get<T>(string objectName, params object[] args)
        {
            return (T)Context.GetObject(objectName, args);
        }

        /// <summary>
        /// Gets the specified args.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="args">The args.</param>
        /// <returns></returns>
        public static T Get<T>(params object[] args)
        {
            return (T)Context.GetObject(typeof(T).Name, args);
        }

        /// <summary>
        /// Creates this instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T Create<T>()
        {
            return (T)Context.CreateObject(typeof(T).Name, typeof(T), null);
        }

        /// <summary>
        /// Creates this instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T Create<T>(params object[] args)
        {
            return (T)Context.CreateObject(typeof(T).Name, typeof(T), args);
        }

        /// <summary>
        /// Configurates the specified existing.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="existing">The existing.</param>
        public static void Configurate<T>(T existing)
        {
            Context.ConfigureObject(existing, typeof(T).FullName);
        }

        /// <summary>
        /// Gets the context.
        /// </summary>
        /// <value>The context.</value>
        private static IApplicationContext Context
        {
            get
            {
                lock (SyncLock)
                {
                    return _context ?? (_context = ContextRegistry.GetContext());
                }
            }
        }

        private static IApplicationContext _context;



        private static readonly object SyncLock = new object();

        /// <summary>
        /// Registers the singleton.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="singleton">The singleton.</param>
        public static void RegisterSingleton<T>(object singleton)
        {
            ((IConfigurableApplicationContext)Context).ObjectFactory.RegisterSingleton(typeof(T).Name, singleton);
        }

        /// <summary>
        /// Gets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public static object Get(string name)
        {
            return Context.GetObject(name);
        }

        /// <summary>
        /// Gets the object.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="args">The args.</param>
        /// <returns></returns>
        public static object GetObject(string name, object[] args)
        {
            return Context.GetObject(name, args);
        }



    }
}
